Skip to content

Fail on non-Object input for JSONObject instead of quietly returning empty Object - #90

Merged
cowtowncoder merged 6 commits into
FasterXML:3.xfrom
pjfanning:fix-jsonorg-object-token-check
Sep 15, 2026
Merged

cowtowncoder merged 6 commits into
FasterXML:3.xfrom
pjfanning:fix-jsonorg-object-token-check

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Problem

JSONArrayDeserializer verifies that it was given a START_ARRAY (guard added for [datatype-json-org#15]), but JSONObjectDeserializer never got the equivalent check:

JSONObject ob = new JSONObject();
JsonToken t = p.currentToken();
if (t == JsonToken.START_OBJECT) {
    t = p.nextToken();
}
for (; t == JsonToken.PROPERTY_NAME; t = p.nextToken()) {

When the current token is not START_OBJECT, the loop simply does not run: an empty JSONObject is returned and the parser is left pointing in the middle of the value that was never consumed.

This silently produces wrong values rather than reporting an error:

input (as List<JSONObject>) before expected
[{"a":1},42,{"b":2}] [{"a":1}, {}, {"b":2}] error
[{"a":1},[7,8],{"b":2}] [{"a":1}, {}, {}, {}] — 4 elements, all data lost error

The second case desyncs the parser outright; it only surfaces at all because FAIL_ON_TRAILING_TOKENS is enabled by default.

Fix

Add the matching guard, worded like the Array one, so both deserializers behave consistently:

Unexpected token (VALUE_NUMBER_INT), expected START_OBJECT for `org.json.JSONObject` value

Entry with a PROPERTY_NAME is still permitted, since a deserializer may be invoked with the parser already positioned inside the Object — TypeInformationTest continues to pass.

Tests

New FailOnNonObjectTest (7 cases): number/string/array input, the two list cases above that previously corrupted data, plus checks that {} and well-formed Object lists still work.

Full json-org suite: 19 tests, all green.

pjfanning and others added 3 commits September 9, 2026 10:09
…ning empty Object

`JSONArrayDeserializer` verifies it is given a START_ARRAY (added for
[datatype-json-org#15]), but `JSONObjectDeserializer` never got the equivalent
check. It reads `currentToken()` and, when it is not START_OBJECT, simply falls
through the property loop -- returning an empty `JSONObject` and leaving the
parser pointing in the middle of the value it did not consume.

That silently corrupts values rather than reporting an error:

    [{"a":1},42,{"b":2}]     -> [{"a":1}, {}, {"b":2}]
    [{"a":1},[7,8],{"b":2}]  -> [{"a":1}, {}, {}, {}]

Add the matching guard, wording it like the Array one. Entry with a
PROPERTY_NAME is still allowed, since deserializers may be invoked with the
parser already positioned inside the Object.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cowtowncoder cowtowncoder added the json-org Issue related to json-org module label Sep 15, 2026
@cowtowncoder cowtowncoder added this to the 3.3.0 milestone Sep 15, 2026
@cowtowncoder cowtowncoder changed the title (json-org) Fail on non-Object input for JSONObject instead of quietly returning empty Object Fail on non-Object input for JSONObject instead of quietly returning empty Object Sep 15, 2026
@cowtowncoder
cowtowncoder merged commit 08ec56f into FasterXML:3.x Sep 15, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

json-org Issue related to json-org module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants